;;;Chapter 5 Code
;;Page 64
;Code to get destructive and non-destructive version of different CL functions
(defvar *!equivs* (make-hash-table))

(defun def! (fn1 fn2)
  (setf (gethash fn1 *!equivs*) fn2))

(defun ! (fn1)
  (or (gethash fn1 *!equivs*)
      fn1))


;;Memoizing 
;Page 65
(defun memoize (fn)
  (let ((cache (make-hash-table :test #'equal)))
    #'(lambda (&rest args)
        (format t "Values ~A for ~A ~%" (gethash args cache) args)
        (multiple-value-bind (val exist) (gethash args cache)
          (if exist 
            val 
            (setf (gethash args cache)
                  (apply fn args)))))))

;;Composing function
;Page 66
(defun compose (&rest fns)
  (labels ((rec (fns val)
                (if (null fns)
                  val 
                  (apply (car fns) 
                         (let ((ret (rec (cdr fns) val)))
                           (if (listp ret)
                             ret
                             (list ret)))))))
    #'(lambda (&rest args)
        (rec fns args))))

(defun compose2 (&rest fns)
  (let ((lastFn (car (last fns)))
        (allFns (butlast fns)))
    #'(lambda (&rest args)
        (reduce #'funcall
                allFns
                :from-end t
                :initial-value (apply lastFn args)))))
                

      
